
from sqlalchemy import and_
from datetime import datetime

from app.dao import Session
from app.models import Group,GroupDetail,User
from app.parameter import CreateGroupParam,DeleteGroupParam,QueryGroupParam
from app.utils import Response, signatureDecode,signatureEncode
from app.constant import ERRORCODE
from utils import DEBUG,ERROR


class GroupService():
    # 创建者权限
    PERMISSION_CREATE = 4
    # 邀请者权限 + 管理员权限
    PERMISSION_INVITE = 2
    # 群组知识库写权限
    PERMISSION_WRITE = 1
    # 默认权限
    PERMISSION_DEFAULT = 0
    # 邀请码生成密钥
    SIGNATURE_KEY = "sd23@324!@ds23#$#34#$asdas#SD"

    @staticmethod
    def judgeGroup(userId :int, groupId :int, session):
        return session.query(Group).filter(and_(Group.user_id == userId, Group.group_id == groupId)).first()
        

    @staticmethod
    def createGroup(createGroupParam :CreateGroupParam):
        try:
            with Session() as session:
                groupDetail = session.query(GroupDetail).filter(GroupDetail.group_name == createGroupParam.groupName).first()
                if groupDetail != None:
                    return Response(ERRORCODE.REQUEST_GROUPNAME_ALREADY_EXIST)
                groupDetail = GroupDetail(user_id = createGroupParam.userId, group_name = createGroupParam.groupName)
                session.add(groupDetail)
                # 获取自增主键
                session.flush()
                group = Group(group_id = groupDetail.id, user_id = createGroupParam.userId, permission = GroupService.PERMISSION_CREATE)
                session.add(group)
                session.commit()
                return Response(ERRORCODE.RESPONSE_SUCCESS)
        except Exception as e:
            ERROR(e)
            return Response(ERRORCODE.RESPONSE_DATABASE_OPERATION_ERROR, None)
        
    @staticmethod
    def deleteGroup(deleteGroupParam :DeleteGroupParam):
        try:
            with Session() as session:
                # 查询
                group = session.query(GroupDetail)\
                    .filter(and_(GroupDetail.id == deleteGroupParam.groupId, GroupDetail.user_id == deleteGroupParam.userId)).first()
                if group == None:
                    return Response(ERRORCODE.REQUEST_NOT_FOUND_ERROR, "未找到群组")
                # 删除
                session.query(GroupDetail).filter(and_(GroupDetail.user_id == deleteGroupParam.userId, GroupDetail.id == deleteGroupParam.groupId)).delete()
                session.commit()
                return Response(ERRORCODE.RESPONSE_SUCCESS)
        except Exception as e:
            ERROR(e)
            return Response(ERRORCODE.RESPONSE_DATABASE_OPERATION_ERROR, None)
    
    # 获取用户加入的群组
    @staticmethod
    def getGroups(userId : int):
        try:
            with Session() as session:
                groups = session.query(Group, GroupDetail).join(GroupDetail, Group.group_id == GroupDetail.id).\
                    filter(Group.user_id == userId).order_by(Group.permission.desc()).all()
                
                data = []
                for i in groups:
                    group = i[0].to_dict()
                    groupDetail = i[1].to_dict()
                    tmp = dict()
                    tmp["group_id"] = groupDetail["id"]
                    tmp["permission"] = group["permission"]
                    tmp["group_name"] = groupDetail["group_name"]
                    tmp["create_at"] = groupDetail["create_at"]
                    tmp["join_at"] = groupDetail["create_at"]
                    data.append(tmp)
                return Response(ERRORCODE.RESPONSE_SUCCESS, data)
        except Exception as e:
            ERROR(e)
            return Response(ERRORCODE.RESPONSE_DATABASE_OPERATION_ERROR, None) 
    
    # 查询特定群组成员
    @staticmethod
    def getGroup(queryGroupParam :QueryGroupParam):
        try:
            with Session() as session:
                groups = session.query(Group, User).join(User, Group.user_id == User.id).\
                    filter(Group.group_id == queryGroupParam.groupId).\
                        with_entities(User.id, User.nickname, User.avatar, Group.permission, Group.create_at).\
                            order_by(Group.permission.desc()).all()
                data = []
                for i in groups:
                    tmp = dict()
                    tmp["user_id"] = i[0]
                    tmp["nickname"] = i[1]
                    tmp["avatar"] = i[2]
                    tmp["permission"] = i[3]
                    tmp["join_at"] = i[4]
                    
                    data.append(tmp)
                return Response(ERRORCODE.RESPONSE_SUCCESS, data)
        except Exception as e:
            ERROR(e)
            return Response(ERRORCODE.RESPONSE_DATABASE_OPERATION_ERROR, None)
    
    @staticmethod
    def getInvationCode(groupId :int, userId :int, permission :int, options :dict):
        # 权限判断
        with Session() as session:
            group = GroupService.judgeGroup(userId=userId, groupId=groupId, session=session)
            if group == None:
                return Response(ERRORCODE.REQUEST_NOT_FOUND_ERROR, message="do not find the group!");
            
            group = group.to_dict()
            if int(group["permission"]) <= permission:
                return Response(ERRORCODE.REQUEST_HAVE_NO_PERMISSION, "You have not permission to give the permission !")
        
        exp = 0
        if options != None:
            if 'exp' in options.keys():
                exp = options['exp']
            else:
                # 默认十分钟
                exp = datetime.now().timestamp() + 10 * 60
        else:
            exp = datetime.now().timestamp() + 10 * 60
        
        signature = signatureEncode({"groupId": groupId, "permission": permission}, int(exp), GroupService.SIGNATURE_KEY)
        
        return Response(ERRORCODE.RESPONSE_SUCCESS, signature)
        
    @staticmethod
    def checkInvationCode(signature :str, userId):
        try:
            data = signatureDecode(signature, GroupService.SIGNATURE_KEY)
        except Exception as e:
            raise e
            return Response(ERRORCODE.REQUEST_SIGNATRUE_ERROR)
        
        if data == None:
            return Response(ERRORCODE.REQUEST_SIGNATRUE_ERROR)
        
        try:
            # 查询群组
            with Session() as session:
                groupDetail = session.query(GroupDetail).filter(GroupDetail.id == data["groupId"]).first()
                if groupDetail == None:
                    return Response(ERRORCODE.REQUEST_SIGNATRUE_ERROR)
                group = GroupService.judgeGroup(userId, data["groupId"], session)
                if group != None:
                    return Response(ERRORCODE.REQUEST_ERROR, message=" You have already in the group!")
                group = Group(group_id = data['groupId'], permission = data['permission'],user_id = userId)
                session.add(group)
                session.commit()
                return Response(ERRORCODE.RESPONSE_SUCCESS)
            
        # 加入群组
        except Exception as e:
            ERROR(e)
            return Response(ERRORCODE.RESPONSE_DATABASE_OPERATION_ERROR)
        
    @staticmethod
    def exitGroup(queryGroupParam :QueryGroupParam):
        try:
            with Session() as session:
                # 查询
                group = GroupService.judgeGroup(queryGroupParam.userId, queryGroupParam.groupId, session)
                if group == None:
                    return Response(ERRORCODE.REQUEST_NOT_FOUND_ERROR, message=" No find the group!")
                group_dict = group.to_dict()
                if int(group_dict["permission"]) >= GroupService.PERMISSION_CREATE:
                    return Response(ERRORCODE.REQUEST_HAVE_NO_PERMISSION, message=" You own the group! So you can just delete the group instead of exit!")
                # 删除
                session.query(Group).filter(and_(Group.user_id == queryGroupParam.userId, Group.group_id == queryGroupParam.groupId)).delete()
                session.commit()
                return Response(ERRORCODE.RESPONSE_SUCCESS)
        except Exception as e:
            ERROR(e)
            return Response(ERRORCODE.RESPONSE_DATABASE_OPERATION_ERROR, None)